构建一个 springmvc 简单应用 相关的依赖:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 <packaging > war</packaging > <dependencies > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-webmvc</artifactId > </dependency > <dependency > <groupId > org.thymeleaf</groupId > <artifactId > thymeleaf-spring6</artifactId > </dependency > <dependency > <groupId > jakarta.servlet</groupId > <artifactId > jakarta.servlet-api</artifactId > <scope > provided</scope > </dependency > </dependencies > <build > <finalName > my-app-${project.version}</finalName > <plugins > <plugin > <groupId > org.apache.maven.plugins</groupId > <artifactId > maven-compiler-plugin</artifactId > <version > 3.11.0</version > <configuration > <source > 17</source > <target > 17</target > <compilerArgs > <arg > -parameters</arg > </compilerArgs > </configuration > </plugin > <plugin > <groupId > org.apache.maven.plugins</groupId > <artifactId > maven-war-plugin</artifactId > <version > 3.3.2</version > </plugin > </plugins > </build >
配置文件的方式 web.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 <?xml version="1.0" encoding="UTF-8" ?> <web-app xmlns ="https://jakarta.ee/xml/ns/jakartaee" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation ="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_6_0.xsd" version ="6.0" > <filter > <filter-name > CharacterEncodingFilter</filter-name > <filter-class > org.springframework.web.filter.CharacterEncodingFilter</filter-class > <init-param > <param-name > encoding</param-name > <param-value > UTF-8</param-value > </init-param > <init-param > <param-name > forceResponseEncoding</param-name > <param-value > true</param-value > </init-param > </filter > <filter-mapping > <filter-name > CharacterEncodingFilter</filter-name > <url-pattern > /*</url-pattern > </filter-mapping > <filter > <filter-name > HiddenHttpMethodFilter</filter-name > <filter-class > org.springframework.web.filter.HiddenHttpMethodFilter</filter-class > </filter > <filter-mapping > <filter-name > HiddenHttpMethodFilter</filter-name > <url-pattern > /*</url-pattern > </filter-mapping > <servlet > <servlet-name > springmvc</servlet-name > <servlet-class > org.springframework.web.servlet.DispatcherServlet</servlet-class > <init-param > <param-name > contextConfigLocation</param-name > <param-value > classpath:spring-mvc.xml</param-value > </init-param > <load-on-startup > 1</load-on-startup > <multipart-config > <location > </location > <max-file-size > 2097152</max-file-size > <max-request-size > 4194304</max-request-size > <file-size-threshold > 0</file-size-threshold > </multipart-config > </servlet > <servlet-mapping > <servlet-name > springmvc</servlet-name > <url-pattern > /</url-pattern > </servlet-mapping > </web-app >
spring-mvc.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 <?xml version="1.0" encoding="UTF-8" ?> <beans xmlns ="http://www.springframework.org/schema/beans" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xmlns:context ="http://www.springframework.org/schema/context" xmlns:mvc ="http://www.springframework.org/schema/mvc" xsi:schemaLocation ="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd" > <context:component-scan base-package ="com.demo.controller" /> <mvc:annotation-driven /> <bean id ="templateResolver" class ="org.thymeleaf.spring6.templateresolver.SpringResourceTemplateResolver" > <property name ="order" value ="1" /> <property name ="characterEncoding" value ="UTF-8" /> <property name ="prefix" value ="/WEB-INF/templates/" /> <property name ="suffix" value =".html" /> <property name ="templateMode" value ="HTML" /> </bean > <bean id ="templateEngine" class ="org.thymeleaf.spring6.SpringTemplateEngine" > <property name ="templateResolver" ref ="templateResolver" /> </bean > <bean class ="org.thymeleaf.spring6.view.ThymeleafViewResolver" > <property name ="templateEngine" ref ="templateEngine" /> <property name ="characterEncoding" value ="UTF-8" /> </bean > <mvc:resources mapping ="/static/**" location ="/static/" /> <bean id ="multipartResolver" class ="org.springframework.web.multipart.support.StandardServletMultipartResolver" /> </beans >
LoginController:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 @Controller public class LoginController { @GetMapping("/login") public String showLoginPage () { return "login" ; } @PostMapping("/doLogin") public String doLogin (String username, String password, HttpSession session, Model model) { if ("admin" .equals(username) && "123" .equals(password)) { session.setAttribute("user" , username); return "redirect:/index" ; } model.addAttribute("error" , "账号或密码错误" ); return "login" ; } @GetMapping("/index") public String index () { return "index" ; } }
login.html:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <!DOCTYPE html > <html xmlns:th ="http://www.thymeleaf.org" > <head > <title > 登录 - Owlias Evolution</title > </head > <body > <form th:action ="@{/doLogin}" method ="post" > <input type ="text" name ="username" placeholder ="用户名" /> <input type ="password" name ="password" placeholder ="密码" /> <button type ="submit" > 登录</button > </form > <p th:if ="${error}" th:text ="${error}" style ="color:red;" > </p > </body > </html >
index.html:
1 2 3 4 5 6 7 8 9 10 <!DOCTYPE html > <html xmlns:th ="http://www.thymeleaf.org" > <head > <title > 首页 - Owlias</title > </head > <body > <h1 > 欢迎回来, <span th:text ="${session.user}" > 访客</span > !</h1 > <a th:href ="@{/logout}" > 安全退出</a > </body > </html >
全注解的方式 WebInitializer:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 import jakarta.servlet.Filter;import org.springframework.web.filter.CharacterEncodingFilter;import org.springframework.web.filter.HiddenHttpMethodFilter;import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;public class WebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class<?>[] getRootConfigClasses() { return null ; } @Override protected Filter[] getServletFilters() { CharacterEncodingFilter encodingFilter = new CharacterEncodingFilter (); encodingFilter.setEncoding("UTF-8" ); encodingFilter.setForceResponseEncoding(true ); HiddenHttpMethodFilter hiddenHttpMethodFilter = new HiddenHttpMethodFilter (); return new Filter []{encodingFilter, hiddenHttpMethodFilter}; } @Override protected Class<?>[] getServletConfigClasses() { return new Class [] { WebMvcConfig.class }; } @Override protected String[] getServletMappings() { return new String [] { "/" }; } @Override protected void customizeRegistration (jakarta.servlet.ServletRegistration.Dynamic registration) { registration.setMultipartConfig(new jakarta .servlet.MultipartConfigElement("" , 2097152 , 4194304 , 0 )); } }
WebMvcConfig:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.ComponentScan;import org.springframework.context.annotation.Configuration;import org.springframework.web.servlet.config.annotation.EnableWebMvc;import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;import org.thymeleaf.spring6.SpringTemplateEngine;import org.thymeleaf.spring6.templateresolver.SpringResourceTemplateResolver;import org.thymeleaf.spring6.view.ThymeleafViewResolver;import org.thymeleaf.templatemode.TemplateMode;@Configuration @EnableWebMvc @ComponentScan("com.demo.controller") public class WebMvcConfig implements WebMvcConfigurer { @Bean public SpringResourceTemplateResolver templateResolver () { SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver (); resolver.setPrefix("/WEB-INF/templates/" ); resolver.setSuffix(".html" ); resolver.setCharacterEncoding("UTF-8" ); resolver.setTemplateMode(TemplateMode.HTML); return resolver; } @Bean public SpringTemplateEngine templateEngine () { SpringTemplateEngine engine = new SpringTemplateEngine (); engine.setTemplateResolver(templateResolver()); return engine; } @Bean public ThymeleafViewResolver viewResolver () { ThymeleafViewResolver vr = new ThymeleafViewResolver (); vr.setTemplateEngine(templateEngine()); vr.setCharacterEncoding("UTF-8" ); return vr; } @Override public void addResourceHandlers (ResourceHandlerRegistry registry) { registry.addResourceHandler("/static/**" ).addResourceLocations("/static/" ); } }
其他配置与xml的方式完全相同。
常用到的获取参数的注解 @RequestMappring 可以用在类上或者方法上,用来设置请求与处理器的匹配关系 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 @Controller @RequestMapping("/demo/params") public class ParamTestController { } @RequestMapping( value = {"/test01", "test01.do", "/tes?01", "/tes*01", "test01/**"}, // or,支持ant风格的路径 method = {RequestMethod.GET, RequestMethod.POST}, // or params = {"username", "!where", "myReferer=login", "myUserAgent!=IE"}, // and headers = {"Host=localhost:8080", "Referer"}, // and(用法与 params 完全一样) consumes = {"application/x-www-form-urlencoded", "application/json"}, // 支持的请求 Content-Type,or produces = {"text/html;charset=UTF-8", "application/json;charset=UTF-8"} // 设置响应头中的 Content-Type,or ) public String test01 () { }
@PathVariable 主要作用是将占位符表示的数据赋值给控制器方法的形参。
1 2 3 4 5 6 @GetMapping("/test02/{id}/{name}") public String test02 (@PathVariable("id") Long id, @PathVariable(value = "name", required = false) String name) { System.out.println(id + " " + name); return "index" ; }
@RequestParam 主要作用就是获取请求参数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 @PostMapping("/doLogin") public String doLogin (@RequestParam(value = "username") String username, @RequestParam(value = "password") String password, @RequestParam(value = "rememberMe", required = false, defaultValue = "false") Boolean rememberMe, @RequestParam(value = "os", required = false) String[] os, HttpSession session, Model model) { if ("admin" .equals(username) && "123" .equals(password)) { session.setAttribute("user" , username); return "redirect:/index" ; } model.addAttribute("error" , "账号或密码错误" ); return "login" ; }
1 2 3 4 5 6 7 8 9 10 <form th:action ="@{/doLogin}" method ="post" > <input type ="text" name ="username" placeholder ="用户名" /> <input type ="password" name ="password" placeholder ="密码" /> <br > <br > <input type ="checkbox" name ="os" value ="linux" /> linux <input type ="checkbox" name ="os" value ="mac" /> mac <input type ="checkbox" name ="os" value ="windows" /> windows <br > <br > <button type ="submit" > 登录</button > </form >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 @GetMapping("/test04") public String test04 (@RequestHeader(value = "host", required = true) String host, @RequestHeader(value = "referer", required = false, defaultValue = "http://localhost:8080/index") String referer, @RequestHeader Map<String, Object> cookies, // 请求的所有 header 键值对 @CookieValue(value = "JSESSIONID", required = true) String jsessionId, // 检出 cookie 中的 JSESSIONID 的值 @SessionAttribute("user") Object user, HttpSession session, HttpServletRequest request, HttpServletResponse response) { System.out.println(host + " " + referer); Cookie[] requestCookies = request.getCookies(); for (Cookie cookie : requestCookies) { if ("JSESSIONID" .equals(cookie.getName())) { String value = cookie.getValue(); System.out.println(Objects.equals(jsessionId, value)); } } System.out.println(user); Object userValue = session.getAttribute("user" ); System.out.println(Objects.equals(user, userValue)); return "index" ; }
1 <a th:href ="@{/demo/params/test04(username='admin', myReferer='login')}" > 参数测试04</a >
使用 servlet 原生API 1 2 3 4 5 6 @GetMapping("/test04") public String test04 (HttpServletRequest request, HttpServletResponse response, HttpSession session) { }
通过pojo获取参数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 @Data public class User { private Long id; private String username; private String password; private Integer gender; private List<String> hobby; private Role role; } @Data public class Role { private Long id; private String name; } @PostMapping("/test05") public String test05 (User user) { System.out.println(user); return "index" ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 <form th:action ="@{/demo/params/test05}" method ="post" > <input type ="hidden" name ="id" value ="1" /> <input type ="text" name ="username" placeholder ="用户名" /> <input type ="password" name ="password" placeholder ="密码" /> <br > <br > <input type ="radio" name ="gender" value ="1" /> 男 <input type ="radio" name ="gender" value ="0" /> 女 <br > <br > <input type ="checkbox" name ="hobby" value ="football" /> football <input type ="checkbox" name ="hobby" value ="basketball" /> basketball <input type ="checkbox" name ="hobby" value ="ball" /> ball <br > <br > <input type ="hidden" name ="role.id" value ="1" /> <input type ="text" name ="role.name" value ="common" /> <button type ="submit" > 提交</button > </form > <form th:action ="@{/demo/params/test05}" th:object ="${user}" method ="post" > <input type ="text" name ="username" th:value ="${user?.username}" /> <input type ="text" name ="role.id" th:value ="${user?.role?.id}" /> <input type ="text" name ="role.name" th:value ="${user?.role?.name}" /> <button type ="submit" > 提交</button > </form >
@RequestBody @ResponseBody @RequestBody:将请求体(JSON/XML)直接绑定到方法参数对象上。常用于 “application/json” 类的请求。
@ResponseBody:告诉 Spring:别找视图解析器了,直接把返回值转成 JSON 发给浏览器。常用于 “application/json” 类的响应。
1 2 3 4 5 6 7 8 9 10 11 @ResponseBody @PostMapping("/simpleHandle") public Emp simpleHandle (@RequestBody Emp emp) { emp.setName(emp.getName() + " (已处理)" ); return emp; }
1 2 3 4 5 6 axios.post ('/api/simpleHandle' , { name : '张三' , age : 25 }).then (res => { console .log ("返回数据:" , res.data ); });
@RequestEntity @ResponseEntity @RequestEntity:封装了包含请求头、请求体、方法等所有信息的强类型容器。
@ResponseEntity:不仅包含响应体,还能自由设置 HTTP 状态码(如 201, 404)和响应头。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 @PostMapping("/check") public ResponseEntity<String> checkEmp (RequestEntity<Emp> requestEntity) { HttpHeaders headers = requestEntity.getHeaders(); Emp emp = requestEntity.getBody(); String userAgent = headers.getFirst("User-Agent" ); System.out.println("来自浏览器: " + userAgent); if (emp != null && emp.getAge() < 18 ) { return ResponseEntity.badRequest().body("未成年人禁止入职" ); } return ResponseEntity.status(HttpStatus.CREATED) .header("Custom-Header" , "Owlias" ) .body("员工 " + emp.getName() + " 验证通过" ); }
1 2 3 4 5 6 7 8 axios.post ('/api/check' , { name : '小明' , age : 16 }).catch (error => { console .log ("状态码:" , error.response .status ); console .log ("后端消息:" , error.response .data ); });
文件上传和下载 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 @Override protected void customizeRegistration (ServletRegistration.Dynamic registration) { registration.setMultipartConfig(new MultipartConfigElement (null , 2097152L , 4194304L , 0 )); } @PostMapping("/upload") public R<String> upload (@RequestPart("file") MultipartFile file) { if (file.isEmpty()) return R.fail("文件不能为空" ); try { String originalName = file.getOriginalFilename(); String suffix = originalName.substring(originalName.lastIndexOf("." )); String fileName = UUID.randomUUID().toString() + suffix; File destDir = new File (uploadPath); if (!destDir.exists()) destDir.mkdirs(); file.transferTo(new File (destDir, fileName)); return R.ok(fileName); } catch (IOException e) { return R.fail("上传失败:" + e.getMessage()); } } @GetMapping("/download/{fileName}") public ResponseEntity<Resource> download (@PathVariable String fileName) { try { Path path = Paths.get(uploadPath).resolve(fileName); Resource resource = new UrlResource (path.toUri()); if (!resource.exists()) return ResponseEntity.notFound().build(); String downloadName = URLEncoder.encode("员工资料_" + fileName, StandardCharsets.UTF_8); return ResponseEntity.ok() .contentType(MediaType.APPLICATION_OCTET_STREAM) .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + downloadName + "\"" ) .body(resource); } catch (Exception e) { return ResponseEntity.internalServerError().build(); } }
1 2 3 4 5 6 7 8 9 <el-upload class ="upload-demo" action ="/api/files/upload" :on-success ="handleUploadSuccess" :on-error ="handleUploadError" name ="file" :limit ="1" > <el-button type ="primary" > 点击上传头像</el-button > </el-upload >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 const handleUploadSuccess = (response ) => { if (response.code === 0 ) { ElementPlus .ElMessage .success ('文件上传成功,标识:' + response.data ); form.avatar = response.data ; } else { ElementPlus .ElMessage .error (response.msg ); } }; const downloadFile = (fileName ) => { window .location .href = `/api/files/download/${fileName} ` ; };
处理xml类型的参数 大多数情况下 JSON 是主流,但在对接银行、医疗或老旧 ERP 系统时,XML 依然是不可或缺的数据交换格式。
Spring MVC 处理 XML 的核心原理与 JSON 一致,都是通过 HttpMessageConverter 实现的。不过,处理 XML 需要额外的 “解密工具”:Jackson XML 扩展。
引入必要依赖:
1 2 3 4 5 <dependency > <groupId > com.fasterxml.jackson.dataformat</groupId > <artifactId > jackson-dataformat-xml</artifactId > <version > 2.15.2</version > </dependency >
为了让 Spring 知道 XML 标签和 Java 属性的对应关系,我们需要使用 JAXB 或 Jackson XML 注解定义定义业务实体类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;import lombok.Data;@Data @JacksonXmlRootElement(localName = "UserRequest") public class UserXml { @JacksonXmlProperty(localName = "UserName") private String name; @JacksonXmlProperty(localName = "UserAge") private Integer age; @JacksonXmlProperty(localName = "DeptName") private String dept; }
业务处理方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 @RestController @RequestMapping("/api/xml") public class XmlController { @PostMapping(value = "/user", consumes = MediaType.APPLICATION_XML_VALUE, produces = MediaType.APPLICATION_XML_VALUE) public UserXml handleXml (@RequestBody UserXml user) { System.out.println("收到 XML 数据:" + user); user.setName(user.getName() + "[已处理]" ); return user; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 const xmlData = ` <UserRequest> <UserName>李四</UserName> <UserAge>28</UserAge> <DeptName>测试部</DeptName> </UserRequest> ` ;axios.post ('/api/xml/user' , xmlData, { headers : { 'Content-Type' : 'application/xml' } }).then (res => { console .log (res.data ); });
域对象共享数居 使用 servlet API 共享数居 1 2 3 4 5 6 7 8 9 @GetMapping("/tset06") public String tset06 (HttpServletRequest request, HttpSession session) { request.setAttribute("request_profile" , "hahaha" ); session.setAttribute("session_user" , "zhangsan" ); ServletContext context = request.getServletContext(); context.setAttribute("context_dict_order" , "desc" ); return "index" ; }
1 2 3 4 5 <div > <p th:text ="${request_profile}" > </p > <p th:text ="${session.session_user} ?: 'session_user 未找到数据'" > </p > <p th:text ="${application.context_dict_order} ?: 'context_dict_order 未找到数据'" > </p > </div >
ModelAndView 共享数据 ModelAndView 可以设置 request 共享(模型)数据,并且设置返回的视图。在 springmvc 中,不管使用哪种方式共享数居,springmvc 底层最终都会将其包装成一个 ModelAndView 对象。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 @GetMapping("/tset07") public ModelAndView tset07 (ModelAndView mv) { mv.addObject("request_profile" , "hehehe" ); mv.setViewName("index" ); System.out.println(mv.getClass().getName()); return mv; } @GetMapping("/tset07") public ModelAndView tset07 () { ModelAndView mv = new ModelAndView (); mv.addObject("request_profile" , "hehehe" ); mv.setViewName("index" ); return mv; }
Model、Map、ModelMap 在 Spring MVC 中,当你把这三者之一写在方法参数时,Spring 传入的通常都是同一个 BindingAwareModelMap 实例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 @GetMapping("/tset08") public String tset08 (Model model) { model.addAttribute("request_profile" , "heihei" ); System.out.println(model.getClass().getName()); return "index" ; } @GetMapping("/tset08") public String tset08 (Map<String, Object> map) { map.put("request_profile" , "xixi" ); System.out.println(map.getClass().getName()); return "index" ; } @GetMapping("/tset08") public String tset08 (ModelMap mm) { mm.addAttribute("request_profile" , "hengheng" ); System.out.println(model.getClass().getName()); return "index" ; }
Map 是根基(JDK 提供)。
ModelMap extends LinkedHashMap<String, Object>,是对 Map 的增强,专门为 Web 开发定制。
Model 是 Spring 为了简化操作而抽象出来的接口。
BindingAwareModelMap extends ModelMap implements Model,是最终干活的 “全能战士”。
SpringMVC 的视图 SpringMVC 中的视图,对应的顶级接口都是 org.springframework.web.servlet.View。视图的作用是渲染数据,将Model中的数据展示给用户。
SpringMVC 视图的种类非常多,默认有两种类型,即转发视图 InternalResourceView 和重定向视图 RedirectView。
当工程中引入了jstl 的依赖,转发视图会自动转换为 JstlView。倘若使用的视图技术为 Thymeleaf,在 springmvc 的配置文件中配置了 Thymeleaf 的视图解析器,那么由此视图解析器解析之后得到的就是 ThymeleafView。
常见的相应视图的写法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 @GetMapping("/tset08") public ModelAndView tset08 (ModelAndView mv) { mv.addObject("request_profile" , "hehehe" ); mv.setViewName("index" ); return mv; } @GetMapping("/tset09") public String tset09 () { return "forward:/index" ; } @GetMapping("/tset10") public String tset10 () { return "redirect:/login" ; }
标题:
SpringMVC 获取请求信息和视图设置相关技术